/**
 * boot v1.5.7
 * (c) 2017 Jorson WHY
 * @license MIT
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) :
  typeof define === 'function' && define.amd ? define(['jquery'], factory) :
  (global.MidwayBoot = factory(global.jQuery));
}(this, (function (jQuery) { 'use strict';

jQuery = 'default' in jQuery ? jQuery['default'] : jQuery;

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  return typeof obj;
} : function (obj) {
  return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};











var classCallCheck = function (instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
};

var createClass = function () {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  return function (Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps);
    return Constructor;
  };
}();

var templateRegExp = /\$\{(.+?)\}/g;
var hexDigits = "0123456789abcdefghijklmnopqrstuvwxyz";

var stringUtils = {
    applyTemplate: function applyTemplate(template, attrs) {
        return template.replace(templateRegExp, function ($0, $1) {
            return attrs[$1] || $0;
        });
    },
    createReg: function createReg(array) {
        return array.length ? new RegExp('^(' + array.join("|") + ')$') : /^$/;
    },
    uuid: function uuid(len) {
        var uuids = [];
        for (var i = 0; i < len; i++) {
            uuids[i] = hexDigits.substr(Math.floor(Math.random() * 36), 1);
        }
        return uuids.join('');
    },
    urlJoin: function urlJoin() {
        var input = arguments;
        var options = {};

        if (_typeof(arguments[0]) === 'object') {
            input = arguments[0];
            options = arguments[1] || {};
        }
        input = Array.prototype.compact.call(input);
        var joined = [].splice.call(input, 0).join('/');
        return normalize(joined, options);
    },
    randomWord: function randomWord(randomFlag, min, max) {
        var str = "",
            range = min,
            arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
        // 随机产生
        if (randomFlag) {
            range = Math.round(Math.random() * (max - min)) + min;
        }
        var pos = -1;
        for (var i = 0; i < range; i++) {
            pos = Math.round(Math.random() * (arr.length - 1));
            str += arr[pos];
        }
        return str;
    }
};

function startWith(str, search) {
    return str.substr(0, search.length) === search;
}

function normalize(str, options) {
    if (startWith(str, 'file://')) {
        str = str.replace(/(\/{0,3})\/*/g, '$1');
    } else {
        str = str.replace(/:\//g, '://');
        str = str.replace(/([^:\s\%\3\A])\/+/g, '$1/');
    }
    str = str.replace(/\/(\?|&|#[^!])/g, '$1');
    str = str.replace(/(\?.+)\?/g, '$1&');
    return str;
}

var MidwayMode = {
    Online: 'online',
    Offline: 'offline'
};

function assert(condition, msg) {
    if (condition) throw new Error("[midway] " + msg);
}

var _head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;

var ScriptRender = {
    /**
     * 添加外部的URL引用
     * @param url 外部URL地址
     * @attrs 额外附加在style标签上的属性
     */
    addStyle: function addStyle() {
        var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
        var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;

        assert(url === undefined, "style url is undefined");
        var element = document.createElement('link');
        element.setAttribute('rel', 'stylesheet');
        element.setAttribute('type', 'text/css');
        element.setAttribute('href', url);
        if (attrs !== undefined) {
            for (var key in attrs) {
                script.setAttribute(key, attr[key]);
            }
        }
        _head.appendChild(element);
        return element;
    },
    /**
     * 添加外部Javascript引用
     * @param url 外部JS地址
     * @attrs 额外附加在script标签上的属性
     */
    addJavascript: function addJavascript(url) {
        var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;

        assert(url === undefined, "script url is undefined");
        var deferred = $.Deferred(),
            script = document.createElement("script");
        script.type = 'text/javascript';
        script.charset = 'utf-8';
        script.async = true;
        script.src = url;
        if (attrs !== undefined) {
            for (var key in attrs) {
                script.setAttribute(key, attr[key]);
            }
        }
        script.onerror = function () {
            console.error("javascript load failure!, URL=" + url);
            deferred.reject();
        };
        script.onload = script.onreadystatechange = function (_, isAbort) {
            if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
                script.onload = script.onreadystatechange = null;
                script = null;
                if (!isAbort) {
                    deferred.resolve();
                } else {
                    deferred.reject();
                    console.error("load javascript abort!, URL=" + url);
                }
            }
        };
        _head.appendChild(script);
        return deferred.promise();
    },
    addEmbedStyle: function addEmbedStyle(code) {
        var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;

        var element = document.createElement("style");
        if (element.styleSheet) {
            element.styleSheet.cssText = code;
        } else {
            element.innerHTML = code;
        }
        if (attrs !== undefined) {
            for (var key in attrs) {
                element.setAttribute(key, attrs[key]);
            }
        }
        _head.appendChild(element);
        return element;
    },
    addEmbedScript: function addEmbedScript(code) {
        var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;

        var element = document.createElement("script");
        element.setAttribute("language", "Javascript");
        element.text = code;
        if (attrs !== undefined) {
            for (var key in attrs) {
                element.setAttribute(key, attrs[key]);
            }
        }
        _head.appendChild(element);
        return element;
    },
    /**
     * 检查外部样式是否引用
     * @param predicate 移除样式的依据, 可以是URL或函数
     * @returns {boolean} 引用情况
     */
    checkStyle: function checkStyle(predicate) {
        var exists = false;
        if (typeof predicate === 'string') {
            $.each(document.head.childNodes, function (index, item) {
                if (item.nodeName === 'LINK' && item.attributes['href'].value === predicate) {
                    exists = true;
                    return false;
                }
            });
        } else if (typeof predicate === 'function') {
            $.each(document.head.childNodes, function (index, item) {
                if ((item.nodeName === 'LINK' || item.nodeName === 'STYLE') && predicate.call(undefined, item)) {
                    exists = true;
                    return false;
                }
            });
        }
        return exists;
    },
    /**
     * 移除外接样式
     * @param predicate 移除样式的依据, 可以是URL或函数
     */
    removeStyle: function removeStyle(predicate) {
        if (typeof predicate === 'string') {
            var url = predicate;
            document.head.childNodes.forEach(function (item) {
                if (item.nodeName === 'LINK' && item.attributes['href'].value === url) {
                    _head.removeChild(item);
                }
            });
        } else if (typeof predicate === 'function') {
            document.head.childNodes.forEach(function (item) {
                if (item.nodeName === 'LINK' && predicate.call(undefined, item)) {
                    _head.removeChild(item);
                }
            });
        }
    },
    removeStyleElement: function removeStyleElement() {
        var element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;

        assert(element === undefined, "style element is undefined");
        _head.removeChild(element);
        element = null;
    }
};

function arrayPolyFill() {
    if (typeof Array.prototype.from !== 'function') {
        Array.prototype.from = function () {
            var toStr = Object.prototype.toString;
            var isCallable = function isCallable(fn) {
                return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
            };
            var toInteger = function toInteger(value) {
                var number = Number(value);
                if (isNaN(number)) {
                    return 0;
                }
                if (number === 0 || !isFinite(number)) {
                    return number;
                }
                return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
            };
            var maxSafeInteger = Math.pow(2, 53) - 1;
            var toLength = function toLength(value) {
                var len = toInteger(value);
                return Math.min(Math.max(len, 0), maxSafeInteger);
            };
            return function from(arrayLike /*, mapFn, thisArg */) {
                var C = this;
                var items = Object(arrayLike);
                if (arrayLike === null) {
                    throw new TypeError('Array.from requires an array-like object - not null or undefined');
                }
                var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
                var T = void 0;
                if (typeof mapFn !== 'undefined') {
                    if (!isCallable(mapFn)) {
                        throw new TypeError('Array.from: when provided, the second argument must be a function');
                    }
                    if (arguments.length > 2) {
                        T = arguments[2];
                    }
                }
                var len = toLength(items.length),
                    A = isCallable(C) ? Object(new C(len)) : new Array(len),
                    k = 0,
                    kValue = void 0;
                while (k < len) {
                    kValue = items[k];
                    if (mapFn) {
                        A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
                    } else {
                        A[k] = kValue;
                    }
                    k += 1;
                }
                A.length = len;
                return A;
            };
        }();
    }

    if (typeof Array.prototype.forEach !== 'function') {
        Array.prototype.forEach = function (callback, thisObj) {
            var T = void 0,
                k = void 0;
            if (this === null) {
                throw new TypeError(' this is null or not defined');
            }
            var O = Object(this),
                len = O.length >>> 0;
            if (typeof callback !== "function") {
                throw new TypeError(callback + ' is not a function');
            }
            if (arguments.length > 1) {
                T = thisObj;
            }
            k = 0;
            while (k < len) {
                var kValue = void 0;
                if (k in O) {
                    kValue = O[k];
                    callback.call(T, kValue, k, O);
                }
                k++;
            }
        };
    }
    //修正NodeList
    if (typeof NodeList.prototype.forEach !== 'function') {
        NodeList.prototype.forEach = Array.prototype.forEach;
    }

    if (typeof Array.prototype.each !== 'function') {
        Array.prototype.each = function (callback, thisObj) {
            var T = void 0,
                k = void 0;

            if (this === null) {
                throw new TypeError(' this is null or not defined');
            }
            var O = Object(this),
                len = O.length >>> 0;
            if (typeof callback !== "function") {
                throw new TypeError(callback + ' is not a function');
            }
            if (arguments.length > 1) {
                T = thisObj;
            }
            k = 0;
            while (k < len) {
                var kValue = void 0;
                if (k in O) {
                    kValue = O[k];
                    callback.call(T, kValue, k, O);
                }
                k++;
            }
        };
    }

    if (typeof Array.prototype.isArray !== 'function') {
        Array.prototype.isArray = function (arg) {
            return Object.prototype.toString.call(arg) === '[object Array]';
        };
    }

    if (typeof Array.prototype.includes !== 'function') {
        Array.prototype.includes = function (searchElement, fromIndex) {
            'use strict';

            if (this === null) {
                throw new TypeError('"this" is null or not defined');
            }
            var o = Object(this),
                len = o.length >>> 0;
            if (len === 0) {
                return false;
            }
            var n = fromIndex | 0;
            var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
            while (k < len) {
                if (o[k] === searchElement) {
                    return true;
                }
                k++;
            }
            return false;
        };
    }

    if (typeof Array.prototype.find !== 'function') {
        Array.prototype.find = function (predicate) {
            'use strict';

            if (this === null) {
                throw new TypeError('Array.prototype.find called on null or undefined');
            }
            if (typeof predicate !== 'function') {
                throw new TypeError('predicate must be a function');
            }
            var list = Object(this),
                length = list.length >>> 0,
                thisArg = arguments[1],
                value = void 0;

            for (var i = 0; i < length; i++) {
                value = list[i];
                if (predicate.call(thisArg, value, i, list)) {
                    return value;
                }
            }
            return undefined;
        };
    }

    if (typeof Array.prototype.findIndex !== 'function') {
        Array.prototype.findIndex = function (predicate) {
            if (this === null) {
                throw new TypeError('Array.prototype.findIndex called on null or undefined');
            }
            if (typeof predicate !== 'function') {
                throw new TypeError('predicate must be a function');
            }
            var list = Object(this),
                length = list.length >>> 0,
                thisArg = arguments[1],
                value = void 0;

            for (var i = 0; i < length; i++) {
                value = list[i];
                if (predicate.call(thisArg, value, i, list)) {
                    return i;
                }
            }
            return -1;
        };
    }

    if (typeof Array.prototype.compact !== 'function') {
        Array.prototype.compact = function () {
            var index = -1,
                length = this === null ? 0 : this.length,
                resIndex = 0,
                result = [];
            while (++index < length) {
                var value = this[index];
                if (value) {
                    result[resIndex++] = value;
                }
            }
            return result;
        };
    }

    if (typeof Array.prototype.insertOf !== 'function') {
        Array.prototype.insertOf = function (index, value) {
            if (this.length < index) {
                throw Error('index can not big than length!');
            }
            this.splice(index, 0, value);
        };
    }
}

arrayPolyFill();

var playerUrl = "${protocol}//${manager}/v0.1/players/${player}/latest_version";
var onlineBase = "${protocol}//${cs}/v0.1/static/esp_developer";
var protocol = window.location.protocol || 'http:';
var bootOptions = {};

var defaultOptions = {
    mode: MidwayMode.Online,
    player: '',
    paths: {
        manager: "esp-developer-service.edu.web.sdp.101.com",
        cs: "cdncs.101.com"
    }
};

var MidwayBoot = function () {
    function MidwayBoot() {
        classCallCheck(this, MidwayBoot);

        if (!MidwayBoot.instance) {
            if (window.MidwayMode === undefined) {
                window.MidwayMode = MidwayMode;
                Object.freeze(window.MidwayMode);
            }
            this.events = {};
            MidwayBoot.instance = this;
        }
        return MidwayBoot.instance;
    }

    createClass(MidwayBoot, [{
        key: "config",
        value: function config() {
            var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

            bootOptions = jQuery.extend(true, defaultOptions, options);
            if (options.events) {
                this.events['onReady'] = options.events.onReady || defaultOnReady;
            }
            if (bootOptions.mode === MidwayMode.Online) {
                loadOnlinePlayerInfo(bootOptions, this._afterScriptLoaded.bind(this));
            } else if (bootOptions.mode === MidwayMode.Offline) {
                loadOfflinePlayerInfo(this._afterScriptLoaded.bind(this));
            }
        }
    }, {
        key: "_afterScriptLoaded",
        value: function _afterScriptLoaded(playerInfo) {
            var _this = this;

            if (window.Midware === undefined || window.Midway === undefined) {
                throw Error('Middleware not finished loading');
            }
            //初始化中间层组件
            if (bootOptions.mode === MidwayMode.Online) {
                Midware.globalConfig({
                    BasePath: protocol + "//" + bootOptions.paths.cs + '/v0.1/static/esp_developer',
                    LanguageBasePath: "languages",
                    StyleBasePath: "style",
                    AssetsBasePath: ""
                });
                Midware.startup({
                    i18n: {
                        configPath: "players/" + playerInfo.code + "/" + playerInfo.version + "/languages",
                        configFile: "language_default.json"
                    },
                    extend: {
                        context: "_"
                    },
                    style: {
                        configPath: "players/" + playerInfo.code + "/" + playerInfo.version,
                        containVersion: true
                    },
                    customPlayer: {
                        code: playerInfo.code,
                        version: playerInfo.version
                    },
                    courseware: {
                        configPath: "players/" + playerInfo.code + "/" + playerInfo.version
                    },
                    async: false
                });
                Midway.config({
                    BasePath: protocol + "//" + bootOptions.paths.cs + '/v0.1/static/esp_developer'
                });
                Midway.runMidway({ code: playerInfo.code, version: playerInfo.version }).done(function () {
                    if (_this.events.onReady && typeof _this.events.onReady === 'function') {
                        //加载完成
                        _this.events.onReady();
                    }
                });
            } else if (bootOptions.mode === MidwayMode.Offline) {
                Midware.globalConfig({ LanguageBasePath: "ref/languages", ComponentBasePath: "ref/js-library" });
                var midwareStartupConfig = { async: false };
                if (bootOptions.extendConfig && typeof bootOptions.extendConfig === 'string') {
                    midwareStartupConfig['courseware'] = { extendConfig: bootOptions.extendConfig };
                }
                Midware.startup(midwareStartupConfig);
                Midway.config({});
                Midway.runMidway().done(function () {
                    if (_this.events.onReady && typeof _this.events.onReady === 'function') {
                        //加载完成
                        _this.events.onReady();
                    }
                });
            } else {
                throw Error('Unrecognized mode');
            }
        }
    }]);
    return MidwayBoot;
}();

var midwayBoot = new MidwayBoot();
Object.freeze(midwayBoot);
function loadOnlinePlayerInfo(options, callback) {
    var requestUrl = stringUtils.applyTemplate(playerUrl, {
        'protocol': protocol,
        'manager': options.paths.manager,
        'player': options.player
    });
    var midwayUrl = void 0,
        midwareUrl = void 0;
    jQuery.ajax({
        url: requestUrl,
        dataType: 'json',
        method: 'GET',
        cache: false,
        async: false
    }).done(function (data) {
        if (data.midware_version) {
            var onlineBasePath = stringUtils.applyTemplate(onlineBase, {
                'protocol': protocol,
                'cs': options.paths.cs
            });
            midwayUrl = stringUtils.urlJoin(onlineBasePath, "modules/InteractionMidware", data.midware_version, "midway/midway.umd.js", "?release=" + data.version);
            midwareUrl = stringUtils.urlJoin(onlineBasePath, "modules/InteractionMidware", data.midware_version, "midway/facade.umd.js", "?release=" + data.version);
            var def1 = ScriptRender.addJavascript(midwayUrl);
            var def2 = ScriptRender.addJavascript(midwareUrl);
            //加载完成
            jQuery.when(def1, def2).done(function () {
                data.code = options.player;
                callback(data);
            });
        }
    });
}

function loadOfflinePlayerInfo(callback) {
    var midwayUrl = 'ref/modules/InteractionMidware/midway/midway.umd.js',
        midwareUrl = 'ref/modules/InteractionMidware/midway/facade.umd.js';

    var def1 = ScriptRender.addJavascript(midwayUrl),
        def2 = ScriptRender.addJavascript(midwareUrl);
    jQuery.when(def1, def2).done(function () {
        callback();
    });
}

function defaultOnReady() {
    console.log("message from default ready");
}

return midwayBoot;

})));
